Skip to content

Enhance support for switch statements - #99

Open
kjw142857 wants to merge 14 commits into
mainfrom
switch-statements
Open

Enhance support for switch statements#99
kjw142857 wants to merge 14 commits into
mainfrom
switch-statements

Conversation

@kjw142857

@kjw142857 kjw142857 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

This PR aims to build on existing support for switch statements by completing the type of selector accepted, in particular narrowing it down to String, integral types or enum types.

Note: For the purpose of creating unit tests, enum support has been created in the compiler. The support in the JVM will be added along with the standard libraries update.

@kjw142857 kjw142857 self-assigned this Aug 10, 2026
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

Coverage report

Caution

Test run failed

St.
Category Percentage Covered / Total
🟡 Statements
73.48% (+0.85% 🔼)
7920/10778
🔴 Branches
60% (+0.65% 🔼)
2653/4422
🟡 Functions
70.72% (+1.18% 🔼)
1401/1981
🟡 Lines
74.5% (+0.99% 🔼)
7455/10007
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🟢
... / enum.test.ts
100% 100% 100% 100%
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟢
... / utils.ts
96.43% (-0.37% 🔻)
94.07% (-0.8% 🔻)
94.44%
96.63% (-0.45% 🔻)
🟡
... / index.ts
68.02% (-4.13% 🔻)
48.36% (-1.31% 🔻)
77.42% (-14.58% 🔻)
76.32% (-4.56% 🔻)
🟡
... / prechecks.ts
60.12% (-22.98% 🔻)
48.72% (-9.35% 🔻)
93.33% (-6.67% 🔻)
67.18% (-21.16% 🔻)
🟢
... / compiler.ts
100%
76.92% (-6.41% 🔻)
100% 100%

Test suite run failed

Failed tests: 2/1159. Failed suites: 1/65.
  ● compiler tests › enums › enum switch and synthetic methods

    cannot resolve symbol "name" in "Color.BLUE.name"

      362 |         const node = curTable.get(key)
      363 |         if (node === undefined) {
    > 364 |           throw new SymbolCannotBeResolvedError(token, name)
          |                 ^
      365 |         }
      366 |         symbolInfos.push(node.info)
      367 |       }

      at src/compiler/symbol-table.ts:364:17
          at Array.forEach (<anonymous>)
      at SymbolTable.forEach [as querySymbol] (src/compiler/symbol-table.ts:333:12)
      at SymbolTable.querySymbol (src/compiler/symbol-table.ts:379:19)
      at Object.queryMethod [as MethodInvocation] (src/compiler/code-generator.ts:1074:43)
      at getExpressionType (src/compiler/code-generator.ts:331:47)
      at getExpressionType (src/compiler/code-generator.ts:1084:48)
          at Array.map (<anonymous>)
      at Object.map [as MethodInvocation] (src/compiler/code-generator.ts:1084:37)
      at compile (src/compiler/code-generator.ts:359:35)
      at Object.compile [as ExpressionStatement] (src/compiler/code-generator.ts:1044:12)
      at compile (src/compiler/code-generator.ts:359:35)
      at compile (src/compiler/code-generator.ts:369:58)
          at Array.forEach (<anonymous>)
      at Object.forEach [as Block] (src/compiler/code-generator.ts:368:27)
      at compile (src/compiler/code-generator.ts:359:35)
      at CodeGenerator.compile [as generateCode] (src/compiler/code-generator.ts:2063:47)
      at generateCode (src/compiler/code-generator.ts:2103:24)
      at Compiler.compileMethod (src/compiler/compiler.ts:606:19)
      at compileMethod (src/compiler/compiler.ts:537:37)
          at Array.forEach (<anonymous>)
      at Compiler.forEach [as handleClassBody] (src/compiler/compiler.ts:537:19)
      at Compiler.handleClassBody [as compileClass] (src/compiler/compiler.ts:125:10)
      at compileClass (src/compiler/compiler.ts:95:32)
          at Array.forEach (<anonymous>)
      at Compiler.forEach (src/compiler/compiler.ts:89:22)
      at compile (src/compiler/index.ts:10:19)
      at runTest (src/compiler/__tests__/__utils__/test-utils.ts:36:28)
      at Object.<anonymous> (src/compiler/__tests__/tests/enum.test.ts:192:30)

  ● compiler tests › enums › enum constructors and instance fields

    Command failed: java -noverify Main > output.log 2> err.log

      39 |     }
      40 |
    > 41 |     execSync('java -noverify Main > output.log 2> err.log', { cwd: tempDir })
         |             ^
      42 |
      43 |     // ignore difference between \r?\n and \n
      44 |     const actualLines = fs.readFileSync(path.join(tempDir, 'output.log'), 'utf-8').split(/\r?\n/).slice(0, -1)

      at runTest (src/compiler/__tests__/__utils__/test-utils.ts:41:13)
      at Object.<anonymous> (src/compiler/__tests__/tests/enum.test.ts:192:30)

Report generated by 🧪jest coverage report action from 52781ca

@kjw142857

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Changes

Enum switch support

Layer / File(s) Summary
Enum type registration and members
src/types/types/classes.ts, src/types/checker/environment.ts, src/types/checker/prechecks.ts
Enum declarations register as EnumClass types. Enum constants, fields, constructors, methods, nested declarations, and the built-in Enum parent are processed.
Enum and switch type checking
src/types/checker/index.ts, src/types/checker/statements.ts, src/types/checker/__tests__/switchStatements.test.ts
The checker validates enum declarations and switch labels. String and enum selectors are accepted, Boolean selectors are rejected, and incompatible enum cases produce errors.
Enum switch code generation
src/compiler/compiler-utils.ts, src/compiler/code-generator.ts
Enum classes emit ACC_ENUM. Enum switch expressions call Enum.ordinal() before integer switch generation. Unsupported-type diagnostics include enum support.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CompilationUnit
  participant prechecks as prechecks.ts
  participant Checker
  participant CodeGenerator
  CompilationUnit->>prechecks: discover and register enum declarations
  prechecks->>Checker: validate enum members and methods
  Checker->>Checker: validate enum switch selectors and labels
  Checker->>CodeGenerator: compile validated enum switch
  CodeGenerator->>CodeGenerator: call Enum.ordinal()
  CodeGenerator->>CodeGenerator: generate integer switch dispatch
Loading

Poem

A rabbit checks each enum name,
Then hops through cases in a row.
Ordinal numbers join the game,
While typed declarations grow.
ACC_ENUM flags sparkle bright—
Switches compile just right.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: expanded switch-statement support, including stricter selector types and enum handling.
Description check ✅ Passed The description directly explains the changeset by identifying the supported switch selector types and the scope of enum support.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch switch-statements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/compiler/code-generator.ts (1)

1407-1424: 🎯 Functional Correctness | 🔴 Critical | 🏗️ Heavy lift

Resolve enum case labels before generating integer switch keys

case RED is an ExpressionName, not a Literal. Line 1416 therefore throws a TypeError before generating switch bytecode. Resolve each enum case constant to its ordinal, matching the selector's Enum.ordinal() conversion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/compiler/code-generator.ts` around lines 1407 - 1424, The integer switch
generation in the case-label processing within the surrounding code-generator
method assumes every CaseLabel expression is a Literal; update it to also
resolve enum ExpressionName constants to their ordinal values, matching the
selector’s Enum.ordinal() conversion, before adding values to caseValues and
caseLabelMap. Preserve literal handling for non-enum cases and default-label
behavior.
🧹 Nitpick comments (5)
src/types/checker/environment.ts (1)

44-46: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Consider adding the Enum base members that the code generator depends on.

The global Enum entry is an empty ClassType. It declares no ordinal(), name(), or compareTo(...) members. src/compiler/code-generator.ts emits INVOKEVIRTUAL java/lang/Enum.ordinal()I for enum switch selectors, so the runtime contract assumes those members exist. A source program that calls selector.ordinal() will fail type checking with CannotFindSymbolError, even though the compiler can emit the call.

Adding at least ordinal() returning int and name() returning String keeps the type environment consistent with the emitted bytecode.

Using ClassType rather than EnumClass for the base is correct here, because checkSwitchExpression must not accept the abstract base as a selector.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/types/checker/environment.ts` around lines 44 - 46, The global Enum entry
in the type environment is missing members required by type checking and
generated bytecode. Update the Enum ClassType declaration to add ordinal()
returning int and name() returning String, preserving it as ClassType so
checkSwitchExpression does not accept the abstract base as a selector.
src/compiler/code-generator.ts (1)

1379-1398: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Narrow the try block and correct the maxStack adjustment.

Two points on this normalization block.

The try at line 1383 wraps both the queryClass lookup and the bytecode emission. queryClass throws SymbolNotFoundError for an unresolved name, which is the case this code intends to tolerate. The current form also swallows any failure from indexMethodrefInfo. Wrap only the lookup, or check for the class before emitting.

Line 1393 sets maxStack to exprStackSize + 1. ordinal() pops the objectref and pushes an int, so the net stack change is zero and the peak stays at exprStackSize. Over-reserving is safe for the verifier, but the extra slot is unnecessary and the expression suggests a growth that does not occur.

♻️ Proposed refactor
     let _resultType = resultType
     if (_resultType && _resultType.startsWith('L') && _resultType !== 'Ljava/lang/String;') {
       const clean = _resultType.replace(/^L|;$/g, '')
+      let classInfo
       try {
-        const classInfo = cg.symbolTable.queryClass(clean)
-        if (classInfo.accessFlags & ACCESS_FLAGS.ACC_ENUM) {
-          // call java.lang.Enum.ordinal() (returns int)
-          cg.code.push(
-            OPCODE.INVOKEVIRTUAL,
-            0,
-            cg.constantPoolManager.indexMethodrefInfo('java/lang/Enum', 'ordinal', '()I')
-          )
-          _resultType = 'I'
-          maxStack = Math.max(maxStack, exprStackSize + 1)
-        }
-      } catch (e) {
-        // ignore: not a known class
+        classInfo = cg.symbolTable.queryClass(clean)
+      } catch {
+        classInfo = undefined // not a known class
+      }
+      if (classInfo && classInfo.accessFlags & ACCESS_FLAGS.ACC_ENUM) {
+        // call java.lang.Enum.ordinal() (returns int)
+        cg.code.push(
+          OPCODE.INVOKEVIRTUAL,
+          0,
+          cg.constantPoolManager.indexMethodrefInfo('java/lang/Enum', 'ordinal', '()I')
+        )
+        _resultType = 'I'
       }
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/compiler/code-generator.ts` around lines 1379 - 1398, Narrow the
try/catch in the enum normalization block around cg.symbolTable.queryClass so
only unresolved-class lookup failures are ignored; let indexMethodrefInfo and
bytecode emission errors propagate. When emitting Enum.ordinal(), update
maxStack using exprStackSize rather than exprStackSize + 1, since the invocation
has zero net stack growth.
src/types/checker/index.ts (2)

585-666: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Extract the shared class-body checking logic instead of duplicating the NormalClassDeclaration branch.

Lines 585-666 duplicate lines 487-583 almost verbatim. Only the declaration list source differs: node.classBody.classBodyDeclarations becomes bodyDecls. The frame setup, the constructor index arithmetic, the field initializer check, the overload index computation, and the counter updates are identical.

Two copies must now stay in sync. A fix applied to one branch will silently miss the other.

Extract a helper that takes classType, the declaration list, and the frame, then call it from both branches.

The as any casts at lines 622, 639, 642, and 656 are also avoidable. The surrounding switch (bodyDeclaration.kind) already narrows the node type, and the equivalent class branch needs no casts. If bodyDecls is typed as any[], type the enum body declaration list properly so the narrowing works.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/types/checker/index.ts` around lines 585 - 666, Extract the duplicated
class-body checking flow from the NormalClassDeclaration and EnumDeclaration
branches into a shared helper accepting classType, declaration list, and frame,
preserving constructor indexing, field initializer checks, method overload
resolution, and declaration counters. Invoke the helper from both branches, and
type the enum declaration list so switch narrowing removes the unnecessary as
any casts in the enum handling.

727-740: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the typed caseConstants field for checker switch labels.

SwitchLabel declares only caseConstants, and the checker AST extractor emits that field. Remove singular-property probing and as any casts. Narrow to the caseConstants variant and iterate over switchLabel.caseConstants. The separate src/ast/astExtractor/statement-extractor.ts model is not used by this checker.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/types/checker/index.ts` around lines 727 - 740, Update the switch-label
handling in the type-checker branch to use only the typed
SwitchLabel.caseConstants field. Remove the singular caseConstant probing and
all any casts, narrow to the caseConstants variant, and iterate directly over
switchLabel.caseConstants while preserving the existing type-checking and error
behavior.
src/types/checker/prechecks.ts (1)

128-159: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Enum constant and method registration look correct.

Registering each enum constant as a field whose type is the enum class matches Java semantics. The constructor and method handling mirrors the NormalClassDeclaration path.

One consistency note: this branch returns on the first error, while the NormalClassDeclaration path accumulates errors and reports them together. Accumulating here would report all enum body problems in one pass.

Also applies to: 173-185

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/types/checker/prechecks.ts` around lines 128 - 159, The EnumDeclaration
processing should accumulate errors from enum constants, constructors, and
methods instead of returning on the first failure. Update the enum registration
loops and createMethodLocal handling to collect TypeCheckerError instances,
continue processing remaining declarations, and return the combined errors after
the enum body has been processed, matching the NormalClassDeclaration path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/compiler/compiler-utils.ts`:
- Around line 9-10: Remove the unreachable enum entry from the class-modifier
mapping, or implement enum declaration parsing separately from
NormalClassDeclaration and assign ACCESS_FLAGS.ACC_ENUM from the declaration
kind rather than classModifier. Ensure ClassModifier remains limited to
supported class modifiers.

In `@src/types/checker/__tests__/switchStatements.test.ts`:
- Around line 76-100: Update the switch statement tests to use Java-valid
unqualified enum labels: change the positive case to case RED and retain the
incompatible case with an unqualified constant from Other, then add coverage for
resolving selector enum constants in case-label scope. Also add a test declaring
an enum at top level to exercise the registration path in prechecks alongside
the existing method-local declarations.

In `@src/types/checker/prechecks.ts`:
- Around line 223-234: The OrdinaryCompilationUnit branch of addClassParents
must traverse nested EnumDeclaration nodes, including enums declared inside
method bodies, before or alongside topLevelClassOrInterfaceDeclarations. Reuse
the existing nested-enum traversal pattern from addClasses or addClassMethods,
and ensure each discovered enum receives the Enum ClassType parent through the
existing parent-assignment logic.
- Around line 18-42: Extract the nested-enum traversal from registerNestedEnums
into one shared helper that descends into each top-level declaration’s children
without visiting the top-level declaration itself. Reuse this helper in the
declaration pass around registerNestedEnums and the pass containing
processNestedEnums, removing their local walkers and duplicate enum processing.
Also invoke the shared helper in the OrdinaryCompilationUnit branch of
addClassParents so nested enums receive the Enum parent. Apply these changes in
src/types/checker/prechecks.ts at lines 18-42, 91-107, and 223-234.
- Around line 160-172: Update the FieldDeclaration handling to convert
bodyNode.unannType with unannTypeToString before passing it to frame.getType,
while preserving the existing fieldType fallback; import unannTypeToString from
its defining module so enum field processing supplies the string expected by
getType.

In `@src/types/checker/statements.ts`:
- Around line 31-34: Update the selector validation around
isPrimitiveIntegralType, isPrimitiveLongType, isStringType, and EnumClass to
also accept boxed integral types Character, Byte, Short, and Integer, reusing
the existing type predicates or classes. Preserve rejection of Boolean and Long,
and add coverage for at least one boxed integral selector in
switchStatements.test.ts.

---

Outside diff comments:
In `@src/compiler/code-generator.ts`:
- Around line 1407-1424: The integer switch generation in the case-label
processing within the surrounding code-generator method assumes every CaseLabel
expression is a Literal; update it to also resolve enum ExpressionName constants
to their ordinal values, matching the selector’s Enum.ordinal() conversion,
before adding values to caseValues and caseLabelMap. Preserve literal handling
for non-enum cases and default-label behavior.

---

Nitpick comments:
In `@src/compiler/code-generator.ts`:
- Around line 1379-1398: Narrow the try/catch in the enum normalization block
around cg.symbolTable.queryClass so only unresolved-class lookup failures are
ignored; let indexMethodrefInfo and bytecode emission errors propagate. When
emitting Enum.ordinal(), update maxStack using exprStackSize rather than
exprStackSize + 1, since the invocation has zero net stack growth.

In `@src/types/checker/environment.ts`:
- Around line 44-46: The global Enum entry in the type environment is missing
members required by type checking and generated bytecode. Update the Enum
ClassType declaration to add ordinal() returning int and name() returning
String, preserving it as ClassType so checkSwitchExpression does not accept the
abstract base as a selector.

In `@src/types/checker/index.ts`:
- Around line 585-666: Extract the duplicated class-body checking flow from the
NormalClassDeclaration and EnumDeclaration branches into a shared helper
accepting classType, declaration list, and frame, preserving constructor
indexing, field initializer checks, method overload resolution, and declaration
counters. Invoke the helper from both branches, and type the enum declaration
list so switch narrowing removes the unnecessary as any casts in the enum
handling.
- Around line 727-740: Update the switch-label handling in the type-checker
branch to use only the typed SwitchLabel.caseConstants field. Remove the
singular caseConstant probing and all any casts, narrow to the caseConstants
variant, and iterate directly over switchLabel.caseConstants while preserving
the existing type-checking and error behavior.

In `@src/types/checker/prechecks.ts`:
- Around line 128-159: The EnumDeclaration processing should accumulate errors
from enum constants, constructors, and methods instead of returning on the first
failure. Update the enum registration loops and createMethodLocal handling to
collect TypeCheckerError instances, continue processing remaining declarations,
and return the combined errors after the enum body has been processed, matching
the NormalClassDeclaration path.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 476c8050-48ea-410f-8baa-c3a0e76dd316

📥 Commits

Reviewing files that changed from the base of the PR and between 8ecede1 and 89ccf30.

📒 Files selected for processing (8)
  • src/compiler/code-generator.ts
  • src/compiler/compiler-utils.ts
  • src/types/checker/__tests__/switchStatements.test.ts
  • src/types/checker/environment.ts
  • src/types/checker/index.ts
  • src/types/checker/prechecks.ts
  • src/types/checker/statements.ts
  • src/types/types/classes.ts

Comment thread src/compiler/compiler-utils.ts
Comment thread src/types/checker/__tests__/switchStatements.test.ts
Comment thread src/types/checker/prechecks.ts
Comment thread src/types/checker/prechecks.ts
Comment thread src/types/checker/prechecks.ts
Comment thread src/types/checker/statements.ts
@martin-henz
martin-henz requested a review from kellywsq03 August 11, 2026 06:54
kjw142857 and others added 11 commits August 26, 2026 15:37
- Updated grammar.pegjs and grammar.ts to add EnumDeclaration parsing
- Added TopLevelClassOrInterfaceDeclaration and ClassMemberDeclaration alternatives for EnumDeclaration
- Added EnumDeclaration, EnumBody, EnumConstantList, and EnumConstant parsing rules
- Created src/compiler/__tests__/tests/enum.test.ts with 3 enum test cases
- Updated src/compiler/__tests__/index.ts to import and run enum tests

Remaining work:
- Run enum compiler tests to verify parsing works
- Implement enum code generation in compiler.ts (enum initialization, synthetic methods)
- Run full test suite to validate no regressions
- Verify enum runtime behavior (ordinal(), name(), values(), valueOf())

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Updated grammar (grammar.pegjs and grammar.ts) to parse enum declarations
  - EnumDeclaration, EnumBody, EnumConstantList, EnumConstant rules
  - Support for optional semicolon after constants and enum body members

- Extended AST types (src/ast/types/classes.ts)
  - Added EnumDeclaration, EnumBody, EnumConstant interfaces
  - Updated ClassDeclaration union to include EnumDeclaration
  - Updated ClassBodyDeclaration to include EnumDeclaration

- Added EnumDeclaration to NodeMap (src/ast/types/ast.ts)

- Updated compiler to handle enum declarations
  - Added compileEnum() method in src/compiler/compiler.ts
  - Updated compile() to route EnumDeclaration through compileEnum()
  - Fixed type signatures to handle both ClassDeclaration and EnumDeclaration
  - Set enum parent to java/lang/Enum and ACC_ENUM flag

- Updated ast-extractor.ts and ec-evaluator/utils.ts to accept ClassDeclaration[]
  - Updated searchMainMtdClass() to filter out enums

- Created src/compiler/__tests__/tests/enum.test.ts with 3 test cases
  - enum switch and synthetic methods
  - enum values returns cloned array
  - enum constructors and instance fields

Status: Enums parse and compile, but synthetic methods not yet implemented.
Tests failing because ordinal(), name(), values(), valueOf() missing.

Next: Implement synthetic enum method generation in compiler.ts

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Added enumOrdinals Map to track enum constant ordinals
- Registered ordinal(), name(), toString(), values(), valueOf() in symbol table
- Fixed FieldInfo insertion to remove invalid 'ordinal' property
- Fixed generateSimpleEnumMethod to use indexFieldrefInfo()

Status: Compiler builds but enum compiler tests fail with:
  1. Switch statement codegen doesn't recognize enum types
  2. Bytecode generation may have structural issues

Next: Fix enum type detection in switch codegen, then debug bytecode generation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* jvm changes

* include try/catch/finally support in code generator

* fix try statement logic

* add parser and type checker integration

* fix finally bug

* add tests and fix syntax error

* Patch grammar logic for throws keyword

* Revert "Patch grammar logic for throws keyword"

This reverts commit 8e933b6.

* Patch grammar logic for throws keyword

* Add fix for execption table finally logic

* Add more tests

* fix finally bug and missing test imports

---------

Co-authored-by: Martin Henz <henz@comp.nus.edu.sg>
* Include current and planned features in README

* Update compiler README

* Delete src/compiler/__tests__/tests/typeConversion.test.ts

* Delete eslint.config.mjs

* Add files via upload

* Add files via upload

---------

Co-authored-by: Martin Henz <henz@comp.nus.edu.sg>
@kjw142857
kjw142857 requested a lite review from Copilot September 2, 2026 03:54
@kjw142857
kjw142857 marked this pull request as ready for review September 2, 2026 03:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The current enum classfile generation path produces invalid/incorrect JVM semantics in key cases (superclass/flags/constructor alignment), which will likely break runtime execution and the newly added enum tests.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR extends switch-statement support by constraining the allowed selector types (String, integral primitives excluding long, and enums) and introduces enum parsing/type-checking/compilation paths to enable enum-based switching end-to-end.

Changes:

  • Added an enum type representation (EnumClass) and updated switch selector validation to permit String and enum selectors.
  • Implemented enum handling across the type-checker prechecks/body checks and expanded switch-case constant handling for differing AST shapes.
  • Added compiler grammar + code generation support for enums (including enum switch lowering) and introduced compiler/type-checker tests for the new behavior.
File summaries
File Description
src/types/types/classes.ts Introduces EnumClass in the type system.
src/types/checker/statements.ts Narrows switch selector acceptance to String/integral/enum.
src/types/checker/prechecks.ts Adds enum registration and enum member processing during prechecks.
src/types/checker/index.ts Adds enum declaration body type-checking and expands switch label constant handling.
src/types/checker/environment.ts Adds a global Enum type entry for enum parenting in the checker environment.
src/types/checker/tests/switchStatements.test.ts Adds switch selector tests for String/Boolean rejection and enum selector/case typing.
src/ec-evaluator/utils.ts Updates main-method class search to account for enum declarations.
src/compiler/symbol-table.ts Extends symbol metadata to track enums and enum constant ordinals.
src/compiler/grammar.ts Adds enum declarations and restricts switch labels to literal/identifier forms.
src/compiler/grammar.pegjs Mirrors grammar changes for enum declarations and switch label parsing.
src/compiler/compiler.ts Adds enum compilation path, enum synthetic members, and compilation ordering adjustments.
src/compiler/compiler-utils.ts Adds enum access flag mapping for class access flags generation.
src/compiler/code-generator.ts Lowers enum switches by converting selector to ordinal and mapping case labels to ordinals.
src/compiler/tests/tests/enum.test.ts Adds end-to-end JVM execution tests for enum features and enum switches.
src/compiler/tests/index.ts Registers the new enum test suite.
src/ast/types/classes.ts Extends compiler AST types to represent enums.
src/ast/types/ast.ts Adds EnumDeclaration to the compiler AST node map.
src/ast/astExtractor/ast-extractor.ts Broadens top-level declaration extraction typing to include enums.
Review details

Suppressed comments (2)

src/types/checker/prechecks.ts:71

  • Frame.setType() returns null | TypeCheckerError (not Error), so this duplicate-type check will never trigger for enums; the method will incorrectly succeed even when the enum type name is already defined.
      if (error instanceof Error) return newResult(null, [new DuplicateClassError(node.location)])

src/compiler/compiler.ts:208

  • When bodyMembers.length !== 0 you skip generating the synthetic enum constructor/ordinal method, but <clinit> still unconditionally invokes <init>(Ljava/lang/String;I)V for each constant (see addEnumStaticInitializer). This will produce invalid bytecode for enums with explicit constructors/fields, and enum constant argument lists are currently ignored (e.g. EARTH(1)).
    if (bodyMembers.length === 0) {
      this.addEnumConstructor()
      this.addEnumOrdinalMethod()
    } else {
      this.handleClassBody(bodyMembers)
    }
  • Files reviewed: 18/18 changed files
  • Comments generated: 4
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +1647 to +1648
})()
: parseInt((label.expression as Literal).literalType.value)
Comment thread src/compiler/compiler.ts
Comment on lines +149 to +151
this.className = enumNode.typeIdentifier
this.parentClassName = 'java/lang/Object'
const accessFlags = generateClassAccessFlags(enumNode.classModifier)
try {
const enumType = new EnumClass(obj.typeIdentifier.identifier)
const err = frame.setType(obj.typeIdentifier.identifier, enumType, obj.typeIdentifier.location)
if (err instanceof Error) {
Comment thread src/compiler/compiler.ts
Comment on lines +376 to +380
// ldc EnumClass.class
bytecode.push(0x12) // ldc
const classRefIndex = this.constantPoolManager.indexClassInfo(this.className)
bytecode.push(classRefIndex & 0xff)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants